package org.hackystat.linkedservicedata.ui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.LinkedList;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import org.hackystat.linkedservicedata.client.LinkedServiceDataClient;
import org.hackystat.linkedservicedata.client.LinkedServiceDataClientException;
import org.hackystat.linkedservicedata.sparql.SparqlFilter;
import org.hackystat.linkedservicedata.vocabularies.HackystatVocab;
import org.restlet.data.MediaType;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import com.hp.hpl.jena.ontology.ObjectProperty;
import com.hp.hpl.jena.rdf.model.ModelFactory;

/**
 * Provides basic functionalities to all the other User Interfaces.
 *
 * @author Myriam Leggieri.
 *
 */
public abstract class LinkedServiceDataUI extends JFrame implements ActionListener, ItemListener {

  /**
   * Auto-generated serial version ID.
   */
  private static final long serialVersionUID = 8599159679450477130L;

  /** LinkedServiceDataClient instance associated with this UI. */
  protected LinkedServiceDataClient lisedClient = null;

  /** URI of the LinkedServiceData host associated with this UI. */
  protected String lisedHostURI = null;

  /** The logged user is the local administer. */
  protected boolean isAdmin = false;

  /** The user is logged in. */
  protected boolean isLogged = false;

  /** RDF serialization language. */
  private String serializationLanguage = null;

  /** Media type preference. */
  private MediaType mediaType = null;

  /** Dimension of the main window. */
  public Dimension winDimension = Toolkit.getDefaultToolkit().getScreenSize();

  /** Dimension of panels included in the main window. */
  public Dimension subwinDimension = new Dimension(winDimension.width - 5, winDimension.height - 5);

  /** Dimension of srollPanes of panels included in the main window. */
  public Dimension subPanelScrollDimension = new Dimension(subwinDimension.width,
      subwinDimension.height - 15);

  /** Dimension of pop-up windows. */
  public Dimension popUpWinDimension = new Dimension(850, 760);

  /** Application Title. */
  private static final String TITLE = "Hackystat - LinkedServiceData Browser";

  /** Name of the logged user */
  protected String loggedUser = null;

  /** Password of the logged user */
  protected String loggedPassw = null;

  /** Buttons dimension. */
  public Dimension buttonDimension = new Dimension(140, 30);

  /** Combo box dimension. */
  public Dimension comboDimension = new Dimension(170, 20);

  /** Triplify buttons dimension. */
  public Dimension triplifyButtonDimension = new Dimension(180, 30);

  /** Size of fonts used for buttons. */
  public final int buttonFontSize = 15;

  /** Size of fonts used within JTextFields. */
  public final int jtextFontSize = 13;

  /** Size of labels. */
  public int labelFontSize = 15;

  /** Size of titles. */
  public int titleFontSize = 20;

  /** Dimension of the users list header's label. */
  public Dimension jtextDimension = new Dimension(200, 25);

  /** Dimension of JList objects */
  public Dimension jlistDimension = new Dimension(245, 75);

  /** Dimension of a little pop-up JDialog */
  public Dimension jdialogAreaDimension = new Dimension(600, 500);

  /** Width of a text area contained in th little pop-up JDialog */
  public int jdialogTextAreaNumCols = 100;

  /** Height of a little pop-up JDialog */
  public int jdialogTextAreaNumRows = 100;

  /** Icon of the OWL logo. */
  public static ImageIcon triplifyIcon = createImageIcon("img/triplify.gif");

  /** Icon of the Refresh logo. */
  public static ImageIcon refreshIcon = createImageIcon("img/refresh.gif");

  /** Icon of the AddNew logo. */
  public static ImageIcon newIcon = createImageIcon("img/new.gif");

  /** Icon of the Search logo. */
  public static ImageIcon searchIcon = createImageIcon("img/search.gif");

  /** Icon of the Clear Cache logo. */
  public static ImageIcon clearIcon = createImageIcon("img/clean.gif");

  /** Index identifying the selected tab. */
  protected int selectedTabIndex = -1;

  public LinkedServiceDataUI() {
    super(LinkedServiceDataUI.TITLE);
    this.lisedHostURI = LinkedServiceDataClient.lisedHost;
    this.serializationLanguage = HackystatConstants.LANG_RDFXML_ABBREV;
    this.mediaType = MediaType.APPLICATION_RDF_XML;
    this.subwinDimension.setSize(winDimension.getWidth() - 10, winDimension.getHeight() - 300);
  }

  /** Returns an ImageIcon, or null if the path was invalid. */
  protected static ImageIcon createImageIcon(String path) {
    java.net.URL imgURL = Start.class.getResource(path);
    if (imgURL != null) {
      return new ImageIcon(imgURL);
    }
    else {
      System.err.println("Couldn't find file: " + path);
      return null;
    }
  }

  protected void initLinkedServiceDataClient(String name, String password)
      throws LinkedServiceDataClientException {
    try {
      this.lisedClient = new LinkedServiceDataClient(name, password, getSerializationLanguage(),
          mediaType, true, true);
      lisedClient.authenticate();
    }
    catch (LinkedServiceDataClientException e) {
      throw e;
    }
    this.loggedUser = name;
    this.loggedPassw = password;
    initComponents(true);
  }

  protected void setSerializationLanguage(String serializationLanguage) {
    this.serializationLanguage = serializationLanguage;
    if (serializationLanguage.equals(HackystatConstants.LANG_N3)) {
      this.mediaType = MediaType.TEXT_RDF_N3;
    }
    else if (serializationLanguage.equals(HackystatConstants.LANG_NTRIPLE)) {
      this.mediaType = new MediaType(HackystatConstants.MEDIA_TYPE_NTRIPLES);
    }
    else if (serializationLanguage.equals(HackystatConstants.LANG_RDFXML)
        || serializationLanguage.equals(HackystatConstants.LANG_RDFXML_ABBREV)) {
      this.mediaType = MediaType.APPLICATION_RDF_XML;
    }
    else if (serializationLanguage.equals(HackystatConstants.LANG_TURTLE)) {
      this.mediaType = new MediaType(HackystatConstants.MEDIA_TYPE_TURTLE);
    }
    if (lisedClient != null) {
      lisedClient.setLanguage(serializationLanguage);
    }
  }

  protected String getSerializationLanguage() {
    return serializationLanguage;
  }

  public boolean isLogged() {
    return this.isLogged;
  }

  public void setLogged(boolean isLogged) {
    this.isLogged = isLogged;
    if (!isLogged) {
      this.loggedUser = null;
      this.loggedPassw = null;
    }
    initComponents(true);
  }

  protected abstract void initComponents(boolean refreshAllTabs);

  public LinkedServiceDataClient getLiSeDClient() {
    return this.lisedClient;
  }

  public JPanel getHeader(ActionListener actionListener, JButton searchButton,
      JButton refreshButton, JButton triplifyAllButton, JButton clearCacheButton, String resource) {
    JPanel horiz = new JPanel();
    horiz.setLayout(new BoxLayout(horiz, BoxLayout.X_AXIS));
    horiz.setBackground(Color.white);
    horiz.add(Box.createHorizontalStrut(winDimension.getSize().width / 4));

    JLabel titleLabel = new JLabel();
    titleLabel = initLabel(titleLabel, resource + " Management:");
    horiz.add(titleLabel);
    horiz.add(Box.createHorizontalStrut(10));

    clearCacheButton = initButton(clearCacheButton, actionListener, triplifyButtonDimension,
        "Clear the server cache for " + "the logged user.");
    horiz.add(clearCacheButton);
    horiz.add(Box.createHorizontalStrut(5));

    searchButton = initButton(searchButton, actionListener, buttonDimension,
        "Search for other developers " + "throughout the Linked Data World.");
    horiz.add(searchButton);
    horiz.add(Box.createHorizontalStrut(5));

    refreshButton = initButton(refreshButton, actionListener, buttonDimension,
        "Clear the local cache and reload data.");
    horiz.add(refreshButton);
    horiz.add(Box.createHorizontalStrut(5));

    triplifyAllButton = initButton(triplifyAllButton, actionListener, triplifyButtonDimension,
        "Get RDF representation of" + " this page.");
    horiz.add(triplifyAllButton);
    horiz.add(Box.createHorizontalGlue());
    return horiz;
  }

  public void clearServerCache() throws LinkedServiceDataClientException {
    getLiSeDClient().clearServerCache(this.loggedUser);
  }

  public JLabel initLabel(JLabel label, String text) {
    label = new JLabel();
    label.setText(text);
    label.setForeground(Color.BLUE);
    label.setFont(new Font("Dialog", java.awt.Font.BOLD, labelFontSize));
    label.setSize(jtextDimension);
    return label;
  }

  public JLabel initTitleLabel(JLabel label, String text) {
    label.setText(text);
    label.setForeground(Color.BLUE);
    label.setFont(new Font("Dialog", java.awt.Font.BOLD, titleFontSize));
    return label;
  }

  public JTextField initTextField(JTextField text, String value, boolean editable) {
    text.setFont(new Font("Dialog", java.awt.Font.PLAIN, jtextFontSize));
    text.setSize(jtextDimension);
    text.setPreferredSize(jtextDimension);
    text.setMaximumSize(jtextDimension);
    text.setMinimumSize(jtextDimension);
    text.setText(value);
    text.setEditable(editable);
    return text;
  }

  public JPasswordField initPasswordField(JPasswordField text, String value, boolean editable) {
    text.setFont(new Font("Dialog", java.awt.Font.PLAIN, jtextFontSize));
    text.setSize(jtextDimension);
    text.setPreferredSize(jtextDimension);
    text.setMaximumSize(jtextDimension);
    text.setMinimumSize(jtextDimension);
    text.setText(value);
    text.setEditable(editable);
    return text;
  }

  public JTextArea initTextArea(JTextArea text, boolean editable) {
    text.setEditable(editable);
    text.setColumns(5);
    text.setRows(5);
    Border loweredetched = BorderFactory.createLineBorder(Color.blue);
    TitledBorder title = BorderFactory.createTitledBorder(loweredetched, "", 0, 0, new Font(
        "Dialog", Font.BOLD, 13), Color.BLUE);
    text.setBorder(title);
    text.setPreferredSize(jlistDimension);
    text.setMaximumSize(jlistDimension);
    text.setMinimumSize(jlistDimension);
    return text;
  }

  public JFormattedTextField initFormattedDateTextField(JFormattedTextField text, Object value,
      boolean editable, String tooltip) {
    text.setFont(new Font("Dialog", java.awt.Font.PLAIN, jtextFontSize));
    text.setSize(jtextDimension);
    text.setPreferredSize(jtextDimension);
    text.setMaximumSize(jtextDimension);
    text.setMinimumSize(jtextDimension);
    text.setText(String.valueOf(value));
    text.setEditable(editable);
    text.setToolTipText(tooltip);
    return text;
  }

  public JButton initButton(JButton button, ActionListener actionListener, Dimension dim,
      String tooltip) {
    button.setFont(new Font("Dialog", java.awt.Font.BOLD, buttonFontSize));
    button.setToolTipText("Get a RDF representation " + "of this page.");
    button.setToolTipText(tooltip);
    button.addActionListener(actionListener);
    button.setSize(dim);
    button.setPreferredSize(dim);
    button.setMaximumSize(dim);
    button.setMinimumSize(dim);
    return button;
  }

  public JComboBox initComboBox(JComboBox combo, ItemListener itemListener) {
    combo.setSize(comboDimension);
    combo.setPreferredSize(comboDimension);
    combo.setMaximumSize(comboDimension);
    combo.setMinimumSize(comboDimension);
    combo.addItemListener(itemListener);
    return combo;
  }

  public JCheckBox initCheckBox(JCheckBox checkBox, ItemListener itemListener, String tooltip,
      boolean enabled, boolean selected) {
    checkBox.setToolTipText(tooltip);
    checkBox.setFont(new Font("Dialog", Font.PLAIN, labelFontSize));
    checkBox.setSelected(selected);
    checkBox.setEnabled(enabled);
    checkBox.setBackground(Color.white);
    checkBox.addItemListener(itemListener);
    return checkBox;
  }

  public JPanel addJListFillingComponent(JLabel label, JTextField text, JButton addButton,
      JButton removeButton, JLabel listLabel, JScrollPane scrollList, String titlePanel) {
    JPanel horiz = new JPanel();
    horiz.setLayout(new BoxLayout(horiz, BoxLayout.X_AXIS));
    horiz.setBackground(Color.white);
    if (titlePanel != null) {
      Border loweredetched = BorderFactory.createLineBorder(Color.blue);
      TitledBorder title = BorderFactory.createTitledBorder(loweredetched, titlePanel, 0, 0,
          new Font("Dialog", Font.BOLD, 13), Color.BLUE);
      horiz.setBorder(title);
    }

    JPanel vertic = new JPanel();
    vertic.setLayout(new BoxLayout(vertic, BoxLayout.Y_AXIS));
    vertic.setBackground(Color.white);
    vertic.add(label);
    vertic.add(Box.createVerticalStrut(1));
    vertic.add(text);
    vertic.add(Box.createVerticalStrut(3));
    vertic.add(addButton);
    vertic.add(Box.createVerticalStrut(1));
    vertic.add(removeButton);
    horiz.add(vertic);
    horiz.add(Box.createHorizontalStrut(5));
    vertic = new JPanel();
    vertic.setLayout(new BoxLayout(vertic, BoxLayout.Y_AXIS));
    vertic.setBackground(Color.white);
    vertic.add(listLabel);
    vertic.add(Box.createVerticalStrut(1));
    vertic.add(scrollList);
    horiz.add(vertic);
    return horiz;
  }

  public JPanel addJListFillingComponent(JLabel label, JTextField text, JButton addButton,
      JButton removeButton, JLabel listLabel, JScrollPane scrollList, String titlePanel,
      JLabel comboLabel, JComboBox combo) {
    JPanel horiz = new JPanel();
    horiz.setLayout(new BoxLayout(horiz, BoxLayout.X_AXIS));
    horiz.setBackground(Color.white);
    if (titlePanel != null) {
      Border loweredetched = BorderFactory.createLineBorder(Color.blue);
      TitledBorder title = BorderFactory.createTitledBorder(loweredetched, titlePanel, 0, 0,
          new Font("Dialog", Font.BOLD, 13), Color.BLUE);
      horiz.setBorder(title);
    }

    JPanel vertic = new JPanel();
    vertic.setLayout(new BoxLayout(vertic, BoxLayout.Y_AXIS));
    vertic.setBackground(Color.white);
    vertic.add(label);
    vertic.add(Box.createVerticalStrut(1));
    vertic.add(text);
    vertic.add(Box.createVerticalStrut(1));
    vertic.add(comboLabel);
    vertic.add(Box.createVerticalStrut(1));
    vertic.add(combo);
    vertic.add(Box.createVerticalStrut(3));
    vertic.add(addButton);
    vertic.add(Box.createVerticalStrut(1));
    vertic.add(removeButton);
    horiz.add(vertic);
    horiz.add(Box.createHorizontalStrut(5));
    vertic = new JPanel();
    vertic.setLayout(new BoxLayout(vertic, BoxLayout.Y_AXIS));
    vertic.setBackground(Color.white);
    vertic.add(listLabel);
    vertic.add(Box.createVerticalStrut(1));
    vertic.add(scrollList);
    horiz.add(vertic);
    return horiz;
  }

  public JList initJList(JList list) {
    list.setOpaque(true);
    list.setFont(new Font("Dialog", Font.PLAIN, labelFontSize));
    list.setBackground(Color.white);
    list.setEnabled(true);
    list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    return list;
  }

  public JScrollPane initJListScrollPane(JScrollPane scroll) {
    scroll.setPreferredSize(jlistDimension);
    scroll.setMaximumSize(jlistDimension);
    scroll.setMinimumSize(jlistDimension);
    return scroll;
  }

  public JScrollPane initSubPanelScrollPane(JScrollPane scroll) {
    int width = subwinDimension.width, height = subwinDimension.height;
    Dimension dim = new Dimension(width, height - 15);
    scroll.setPreferredSize(dim);
    scroll.setMaximumSize(dim);
    scroll.setMinimumSize(dim);
    return scroll;
  }

  public String[] getJListContent(ListModel model) {
    String[] ret = new String[model.getSize()];
    for (int i = 0; i < model.getSize(); i++) {
      ret[i] = String.valueOf(model.getElementAt(i));
    }
    return ret;
  }

  public LinkedList<SparqlFilter> getSparqlFilters(ListModel model) {
    LinkedList<SparqlFilter> ret = new LinkedList<SparqlFilter>();
    SparqlFilter sf = null;
    String str = null;
    String[] split = null;
    for (int i = 0; i < model.getSize(); i++) {
      str = String.valueOf(model.getElementAt(i));
      split = str.split(" ");
      sf = new SparqlFilter();
      sf.setOperator(split[1]);
      ObjectProperty predicate = ModelFactory.createOntologyModel().createObjectProperty(
          HackystatVocab.NS + split[0]);
      sf.setPredicate(predicate);
      if (split[2].matches("\\d+,?\\d+")) {
        split[2] = split[2].replace(",", ".");
        sf.setValue(Double.valueOf(String.valueOf(split[2])));
      }
      else {
        sf.setValue(String.valueOf(split[2]));
      }
      ret.add(sf);
    }
    return ret;
  }

  public void displayQueryResults(String result) {
    JTextArea area = new JTextArea(result);
    area.setColumns(jdialogTextAreaNumCols);
    area.setRows(jdialogTextAreaNumRows);
    area.setEditable(false);
    JScrollPane listScrollPane = new JScrollPane(area);
    listScrollPane.setPreferredSize(jdialogAreaDimension);
    listScrollPane.setMaximumSize(jdialogAreaDimension);
    listScrollPane.setMinimumSize(jdialogAreaDimension);
    JLabel label = new JLabel("Search Results:");
    JPanel center_panel = new JPanel();
    center_panel.setLayout(new BoxLayout(center_panel, BoxLayout.Y_AXIS));
    center_panel.add(label);
    center_panel.add(Box.createVerticalStrut(5));
    center_panel.add(listScrollPane);
    JDialog dialog1 = new JDialog(this, "Search Results");

    dialog1.setLocationRelativeTo(null); // center on screen
    dialog1.setLocation(550, 25); // position by coordinates
    dialog1.toFront(); // raise above other java windows

    dialog1.getContentPane().add(center_panel, BorderLayout.CENTER);
    dialog1.pack();
    dialog1.setVisible(true);

    // dialog1.setDefaultCloseOperation(
    // JDialog.DISPOSE_ON_CLOSE);
    dialog1.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent e) {
        if (JOptionPane.showConfirmDialog(null,
            "Are you sure you want to exit this search result window?",
            "Hackystat - Verification required", JOptionPane.OK_CANCEL_OPTION) == 0) {
          e.getWindow().dispose();
        }
      }
    });
  }

  public String getURIList(String docStr) {
    String ret = "URIs found:";
    Document doc = getLiSeDClient().deserializeDOMDocument(docStr);
    NodeList nodes = doc.getElementsByTagName("uri");
    Node nod = null;
    for (int i = 0; i < nodes.getLength(); i++) {
      nod = nodes.item(i);
      ret += nod.getTextContent() + "\n";
    }
    nodes = doc.getElementsByTagName("literal");
    if (nodes.getLength() != 0) {
      ret += "Literals found:\n";
    }
    for (int i = 0; i < nodes.getLength(); i++) {
      nod = nodes.item(i);
      ret += nod.getTextContent() + "\n";
    }
    return ret;
  }

  public final String getLoggedUser() {
    return this.loggedUser;
  }
}
